// 防止头文件被重复包含
#ifndef __M_HELPER_H__
#define __M_HELPER_H__
// 引入输入输出流库，用于控制台输入输出和文件读写操作
#include <iostream>
// 引入文件流库，用于文件的读写操作
#include <fstream>
// 引入字符串处理库，用于字符串的操作
#include <string>
// 引入向量容器库，用于存储和管理动态数组
#include <vector>
// 引入随机数生成库，用于生成随机数
#include <random>
// 引入字符串流库，用于字符串的格式化和解析
#include <sstream>
// 引入输入输出流操作符库，用于格式化输出
#include <iomanip>
// 引入原子类型库，用于多线程环境下的原子操作
#include <atomic>
// 引入 SQLite 数据库操作库，用于与 SQLite 数据库进行交互
#include <sqlite3.h>
// 引入 C 字符串处理库，用于 C 风格字符串的操作
#include <cstring>
// 引入错误号处理库，用于获取和处理系统错误号
#include <cerrno>
// 引入系统文件状态库，用于获取文件的状态信息
#include <sys/stat.h>
// 引入自定义的日志记录头文件，用于记录程序运行时的日志信息
#include "mq_logger.hpp"

// 定义命名空间 qqmq，用于封装相关的类和函数
namespace qqmq{

// SqliteHelper 类，用于封装 SQLite 数据库的基本操作
class SqliteHelper {
    public:
        // 定义 SQLite 回调函数类型，用于在执行 SQL 语句时处理查询结果
        typedef int(*SqliteCallback)(void*,int,char**,char**);

        // 构造函数，接收数据库文件路径作为参数，并初始化成员变量
        SqliteHelper(const std::string &dbfile) : _dbfile(dbfile), _handler(nullptr){}
        
        // 打开 SQLite 数据库的方法，safe_leve 默认为 SQLITE_OPEN_FULLMUTEX
        bool open(int safe_leve = SQLITE_OPEN_FULLMUTEX) {
            // 调用 sqlite3_open_v2 函数打开或创建 SQLite 数据库
            // 参数依次为：数据库文件名、数据库句柄指针、打开标志、虚拟文件系统名称
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_leve, nullptr);
            // 检查打开数据库是否成功
            if (ret != SQLITE_OK) {
                // 若失败，记录错误日志
                ELOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

        // 执行 SQL 语句的方法，接收 SQL 语句、回调函数和回调函数参数作为参数
        bool exec(const std::string &sql, SqliteCallback cb, void *arg) {
            // 调用 sqlite3_exec 函数执行 SQL 语句
            // 参数依次为：数据库句柄、SQL 语句、回调函数、回调函数参数、错误信息指针
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            // 检查 SQL 语句执行是否成功
            if (ret != SQLITE_OK) {
                // 若失败，记录错误日志
                ELOG("%s \n语句执行失败: %s", sql.c_str(), sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

        // 关闭 SQLite 数据库的方法
        void close() {
            // 检查数据库句柄是否有效，若有效则关闭数据库
            if (_handler) sqlite3_close_v2(_handler);
        }
    private:
        // 数据库文件路径
        std::string _dbfile;
        // SQLite 数据库句柄
        sqlite3 *_handler;
};

// StrHelper 类，用于处理字符串分割操作
class StrHelper{
    public:
        // 静态方法，用于将字符串按指定分隔符分割，并将结果存储在向量中
        static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result) {
            // 记录分隔符位置
            size_t pos, idx = 0;
            // 遍历字符串
            while(idx < str.size()) {
                // 查找分隔符的位置
                pos = str.find(sep, idx);
                // 若未找到分隔符
                if (pos == std::string::npos) {
                    // 将剩余字符串添加到结果向量中
                    result.push_back(str.substr(idx));
                    return result.size();
                }
                // 若分隔符位置与当前索引相同
                if (pos == idx) {
                    // 跳过分隔符
                    idx = pos + sep.size();
                    continue;
                }
                // 将分割的子字符串添加到结果向量中
                result.push_back(str.substr(idx, pos - idx));
                // 更新索引位置
                idx = pos + sep.size();
            }
            return result.size();
        }
};

// UUIDHelper 类，用于生成 UUID
class UUIDHelper {
    public:
        // 静态方法，用于生成 UUID
        static std::string uuid() {
            // 使用随机设备作为随机数种子
            std::random_device rd;
            // 使用 Mersenne Twister 引擎生成随机数
            std::mt19937_64 gernator(rd());
            // 定义均匀分布，范围为 0 到 255
            std::uniform_int_distribution<int> distribution(0, 255);
            // 用于格式化 UUID 字符串
            std::stringstream ss;
            // 生成 UUID 的前 8 个字节
            for (int i = 0; i < 8; i++) {
                // 以十六进制格式输出随机数，并补齐到 2 位
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator) ;
                // 在特定位置插入分隔符
                if (i == 3 || i == 5 || i == 7) {
                    ss << "-";
                }
            }
            // 定义原子类型的序列号，初始值为 1
            static std::atomic<size_t> seq(1);
            // 获取当前序列号，并将序列号加 1
            size_t num = seq.fetch_add(1);
            // 生成 UUID 的后 8 个字节
            for (int i = 7; i >= 0; i--) {
                // 以十六进制格式输出序列号的每一个字节，并补齐到 2 位
                ss << std::setw(2) << std::setfill('0') << std::hex << ((num>>(i*8)) & 0xff);
                // 在特定位置插入分隔符
                if (i == 6) ss << "-";
            }
            // 返回生成的 UUID 字符串
            return ss.str();
        }
};

// FileHelper 类，用于处理文件和目录操作
class FileHelper {
    public:
        // 构造函数，接收文件名作为参数，并初始化成员变量
        FileHelper(const std::string &filename):_filename(filename){}

        // 检查文件是否存在的方法
        bool exists() {
            // 定义文件状态结构体
            struct stat st;
            // 调用 stat 函数获取文件状态
            return (stat(_filename.c_str(), &st) == 0);
        }

        // 获取文件大小的方法
        size_t size() {
            // 定义文件状态结构体
            struct stat st;
            // 调用 stat 函数获取文件状态
            int ret = stat(_filename.c_str(), &st);
            // 检查获取文件状态是否成功
            if (ret < 0) {
                return 0;
            }
            // 返回文件大小
            return st.st_size;
        }

        // 从文件中读取指定长度数据的方法
        bool read(char *body, size_t offset, size_t len) {
            // 以二进制只读模式打开文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in); 
            // 检查文件是否打开成功
            if (ifs.is_open() == false) {
                // 若失败，记录错误日志
                ELOG("%s 文件打开失败！", _filename.c_str());
                return false;
            }
            // 跳转到文件指定位置
            ifs.seekg(offset, std::ios::beg);
            // 读取文件数据
            ifs.read(body, len);
            // 检查文件读取是否成功
            if (ifs.good() == false) {
                // 若失败，记录错误日志
                ELOG("%s 文件读取数据失败！！", _filename.c_str());
                ifs.close();
                return false;
            }
            // 关闭文件
            ifs.close();
            return true;
        }

        // 从文件中读取全部数据的方法
        bool read(std::string &body) {
            // 获取文件大小
            size_t fsize = this->size();
            // 调整字符串大小以容纳文件数据
            body.resize(fsize);
            // 调用 read 方法读取文件数据
            return read(&body[0], 0, fsize);
        }

        // 向文件中写入指定长度数据的方法
        bool write(const char *body, size_t offset, size_t len) {
            // 以二进制读写模式打开文件
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out); 
            // 检查文件是否打开成功
            if (fs.is_open() == false) {
                // 若失败，记录错误日志
                ELOG("%s 文件打开失败！", _filename.c_str());
                return false;
            }
            // 跳转到文件指定位置
            fs.seekp(offset, std::ios::beg);
            // 写入文件数据
            fs.write(body, len);
            // 检查文件写入是否成功
            if (fs.good() == false) {
                // 若失败，记录错误日志
                ELOG("%s 文件写入数据失败！！", _filename.c_str());
                fs.close();
                return false;
            }
            // 关闭文件
            fs.close();
            return true;
        }

        // 向文件中写入字符串数据的方法
        bool write(const std::string &body) {
            // 调用 write 方法写入字符串数据
            return write(body.c_str(), 0, body.size());
        }

        // 重命名文件的方法
        bool rename(const std::string &nname) {
            // 调用 rename 函数重命名文件
            return (::rename(_filename.c_str(), nname.c_str()) == 0);
        }

        // 获取文件父目录的静态方法
        static std::string parentDirectory(const std::string &filename) {
            // 查找最后一个斜杠的位置
            size_t pos = filename.find_last_of("/");
            // 若未找到斜杠
            if (pos == std::string::npos) {
                // 返回当前目录
                return "./";
            }
            // 截取父目录路径
            std::string path = filename.substr(0, pos);
            return path;
        }

        // 创建文件的静态方法
        static bool createFile(const std::string &filename) {
            // 以二进制写模式打开文件
            std::fstream ofs(filename, std::ios::binary | std::ios::out); 
            // 检查文件是否打开成功
            if (ofs.is_open() == false) {
                // 若失败，记录错误日志
                ELOG("%s 文件打开失败！", filename.c_str());
                return false;
            }
            // 关闭文件
            ofs.close();
            return true;
        }

        // 删除文件的静态方法
        static bool removeFile(const std::string &filename) {
            // 调用 remove 函数删除文件
            return (::remove(filename.c_str()) == 0);
        }

        // 创建目录的静态方法
        static bool createDirectory(const std::string &path) {
            // 记录分隔符位置
            size_t pos, idx = 0;
            // 遍历路径
            while(idx < path.size()) {
                // 查找斜杠的位置
                pos = path.find("/", idx);
                // 若未找到斜杠
                if (pos == std::string::npos) {
                    // 创建最后一级目录
                    return (mkdir(path.c_str(), 0775) == 0);
                }
                // 截取子目录路径
                std::string subpath = path.substr(0, pos);
                // 调用 mkdir 函数创建子目录
                int ret = mkdir(subpath.c_str(), 0775);
                // 检查创建目录是否失败且不是因为目录已存在
                if (ret != 0 && errno != EEXIST) {
                    // 若失败，记录错误日志
                    ELOG("创建目录 %s 失败: %s", subpath.c_str(), strerror(errno));
                    return false;
                }
                // 更新索引位置
                idx = pos + 1;
            }
            return true;
        }

        // 删除目录的静态方法
        static bool removeDirectory(const std::string &path) {
            // 构造删除目录的命令
            std::string cmd = "rm -rf " + path;
            // 调用 system 函数执行命令
            return (system(cmd.c_str()) != -1);
        }
    private:
        // 文件名
        std::string _filename;
};
}

// 结束头文件保护
#endif